package devices

import (
	"net"
	"bufio"
	"errors"
	"time"
	"encoding/json"
	"adai.design/homeserver/log"
	"adai.design/homeserver/db"
)

type Reception struct {
	conn     net.Conn
	reader   *bufio.Reader
	register *db.Register

	send   chan *Message
	read   chan *Message
	task   chan *Message
}

func (w *Reception) writeMessage(msg *Message) error {
	if w.send != nil {
		w.send <- msg
		return nil
	}
	buf, _ := json.Marshal(msg)
	_, err := w.conn.Write(append(buf, MessageSlice))
	return err
}

func (w *Reception) readMessage() (*Message, error) {
	data, err := w.reader.ReadSlice(MessageSlice)
	if err != nil {
		return nil, err
	}

	var message Message
	err = json.Unmarshal(data, &message)
	if err != nil {
		return nil, err
	}
	return &message, nil
}

// 登录认证
func (w *Reception) verify() error {
	w.conn.SetDeadline(time.Now().Add(verifyTimeout))
	data, err := w.reader.ReadSlice('\n')
	if err != nil {
		return err
	}

	var message Message
	err = json.Unmarshal(data, &message)
	if err != nil {
		return errors.New("json format error")
	}

	if message.Path != msgPathLogin || message.Method != MsgMethodPost {
		return errors.New("invalid login message type")
	}

	info, err := login(message.Data)
	if err != nil {
		return err
	}

	w.register = info

	msg := &Message{
		Path:   msgPathLogin,
		Method: MsgMethodPost,
		State:  "ok",
	}

	err = w.writeMessage(msg)
	return err
}

func (w *Reception) readLoop() {
	defer close(w.read)
	for {
		w.conn.SetReadDeadline(time.Now().Add(idleTimeout))
		msg, err := w.readMessage()
		if err != nil {
			log.Error("read: %s", err)
			w.conn.Close()
			return
			return
		}
		w.read <- msg
	}
}

func (w *Reception) sendLoop() {
	for msg := range w.send {
		w.conn.SetWriteDeadline(time.Now().Add(idleTimeout))
		buf, _ := json.Marshal(msg)
		_, err := w.conn.Write(append(buf, MessageSlice))
		if err != nil {
			w.conn.Close()
			return
		}
	}
}

func (w *Reception) disconnect() {
	w.conn.Close()
}

func (w *Reception) stop() {
	close(w.task)
}

func (w *Reception) start(ws *Receptions) {
	log.Debug("rm: %s arrive", w.conn.RemoteAddr())
	defer log.Debug("rm: %s leave", w.conn.RemoteAddr())
	defer w.conn.Close()

	// 验证合法性
	err := w.verify()
	if err != nil {
		log.Error("rm: %s err: %s", w.conn.RemoteAddr(), err)
		db.Invalid(&db.InvalidInfo{
			Addr: w.conn.RemoteAddr().String(),
			Time: time.Now(),
			Type: db.InvalidTcp,
		})
		return
	}

	w.read = make(chan *Message, 5)
	go w.readLoop()

	w.send = make(chan *Message, 5)
	defer close(w.send)
	go w.sendLoop()

	w.task = make(chan *Message, 5)

	// 加入在线设备列表
	ws.register <- w
	defer func() {
		ws.unregister <- w
	}()

	//w.writeMessage(&Message{
	//	Path: MsgPathAccessories,
	//	Method: MsgMethodGet,
	//})

eventLoop:
	for {
		select {
		case msg, ok := <-w.read:
			if !ok {
				break eventLoop
			}
			if h, ok := deviceMessageHandleMap[msg.Path]; ok {
				h.handle(w, msg)
			} else {
				// 未知消息，将消息发送给中转站处理
				pkg := &MessagePkg{
					DevId: w.register.Id,
					HomeId: w.register.HomeId,
					Msg: msg,
				}
				ws.recPkg <- pkg
				//log.Error("%s", msg)
			}

		case task, ok := <-w.task:
			if !ok {
				break eventLoop
			}
			w.writeMessage(task)
		}
	}
}


